#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
#include <linux/device.h>


/**
 *  目的： 4.动态切换引脚复用通过c程序
 * 
 * 
 * 老师实现的
 * 
 * 1.配置设备树：
 *  
 * 
 * 	my_gpio:gpio1_a0 {
    	compatible = "mygpio";
		my-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "mygpio_func1", "mygpio_func2";
		pinctrl-0 = <&mygpio_ctrl>;		
		pinctrl-1 = <&i2c3_sda>;
	};

&pinctrl {
	mygpio_func1 {
    	mygpio_ctrl: my-gpio-ctrl {
        	rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
    	};
	};

    mygpio_func2 {
        i2c3_sda: i2c3_sda {
            rockchip,pins = <1 RK_PA0 1 &pcfg_pull_none>;
        };
    };

}
     TRM手册244页
     gpio1a0_sel 
3'h0: GPIO1_A0     第0个复用gpio
3'h1: I2C3_SDAM0    第一个复用i2c 
3'h2: UART3_RXM0 
3'h3: CAN1_RXM0 
3'h4: AUDIOpwmLOUT 
3'h5: ACODEC_ADCDATA 
3'h6: AUDIOpwmLOUTP 

  这个引脚在i2c使用了，注释掉，为了上面测试

 * rk3568.dtsi  把 pinctrl-names 和 pinctrl-0 注释掉
	i2c3: i2c@fe5c0000 {
		compatible = "rockchip,rk3399-i2c";
		reg = <0x0 0xfe5c0000 0x0 0x1000>;
		clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>;
		clock-names = "i2c", "pclk";
		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
	//	pinctrl-names = "default";
	//	pinctrl-0 = <&i2c3m0_xfer>;
		#address-cells = <1>;
		#size-cells = <0>;
		status = "disabled";
	};

    2.在驱动中实现动态切换引脚复用
pinctrl_get_and_lookstate  把上面pinctl设备树描述的2个状态获取，用结构体描述
func1_state、func2_state

  3.  这里#ATTR属性文件点灯的时候一样


  // 在平台总线下创建属性文件
	device_create_file(&pdev->dev,&dev_attr_selectmux);
  第二参数 struct device_attribute 结构体 ， 如何来 



  DEVICE_ATTR_WO(selectmux); 解析 会自动拼接dev_attr_selectmux 结构体

  源码： 
 #define DEVICE_ATTR_WO(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
	这个宏定义了一个结构体，  dev_attr_##_name    dev_attr_selectmux   结构体名字
	这个结构体   struct   device_attribute  dev_attr_selectmux   有读写函数
  

// 结构体复制，写函数定义和 属性  我们设备plateform设备，用到plateform总线，   设备数设备节点会转化为pladtfrom_devices,  这个目录下有属性，  写1， 写0 
   __ATTR_WO(_name)
	#define __ATTR_WO(_name) {						\
	.attr	= { .name = __stringify(_name), .mode = 0200 },		\     属性文件名字  就是传递进去的.name 
	.store	= _name##_store,					\
}
   写函数名字  selectmux_store


   4.测试：  属性节点位置
   /sys/devices/platform/gpio1_a0/selectmux

   如何看现在复用，可以用Io命令看寄存器
  xyd:  cat /sys/kernel/debug/pinctrl/pinctrl/pinmux-pins


  echo 1 > selectmux
   pin 32 (gpio1-0): gpio1_a0 (GPIO UNCLAIMED) function mygpio_fun1 group my-gpio-ctrl

     echo 0 > selectmux
   pin 32 (gpio1-0): gpio1_a0 (GPIO UNCLAIMED) function mygpio_fun2 group i2c3-sda
 */


struct pinctrl *gpio_pinctrl;          // GPIO pinctrl 实例指针
struct pinctrl_state *func1_state;     // 功能1状态
struct pinctrl_state *func2_state;     // 功能2状态
int ret;



ssize_t selectmux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    unsigned long select;
    select = simple_strtoul(buf, NULL, 10);  //把buf转化为unsigned long
    if (select == 1) {
        pinctrl_select_state(gpio_pinctrl, func1_state);     // 选择功能1状态
    } else if (select == 0) {
        pinctrl_select_state(gpio_pinctrl, func2_state);     // 选择功能2状态
    }
    return count;
}
DEVICE_ATTR_WO(selectmux);       // 定义可写的设备属性 selectmux，拼接结构体dev_attr_selectmux

int pinctrl_get_and_lookstate(struct device *dev)
{
    gpio_pinctrl = pinctrl_get(dev);    // 获取GPIO pinctrl实例
    if (IS_ERR(gpio_pinctrl)) {
        printk("pinctrl_get is error\n");
        return -1;
    }

    func1_state = pinctrl_lookup_state(gpio_pinctrl, "mygpio_func1");    // 查找功能1状态
    if (IS_ERR(func1_state)) {
        printk("pinctrl_lookup_state is error\n");
        return -2;
    }

    func2_state = pinctrl_lookup_state(gpio_pinctrl, "mygpio_func2");    // 查找功能2状态
    if (IS_ERR(func2_state)) {
        printk("pinctrl_lookup_state is error\n");
        return -2;
    }

    return 0;
}

// 平台设备初始化函数
static int my_platform_probe(struct platform_device *dev)
{
    printk("This is mydriver_probe\n");
    pinctrl_get_and_lookstate(&dev->dev);     // 获取并查找GPIO pinctrl实例和状态
    device_create_file(&dev->dev, &dev_attr_selectmux);    // 在设备上创建属性文件
    return 0;
}

// 平台设备的移除函数
static int my_platform_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "my_platform_remove: Removing platform device\n");

    // 清理设备特定的操作
    // ...

    return 0;
}


const struct of_device_id of_match_table_id[]  = {
	{.compatible="mygpio"},
};

// 定义平台驱动结构体
static struct platform_driver my_platform_driver = {
    .probe = my_platform_probe,
    .remove = my_platform_remove,
    .driver = {
        .name = "my_platform_device",
        .owner = THIS_MODULE,
		.of_match_table =  of_match_table_id,
    },
};

// 模块初始化函数
static int __init my_platform_driver_init(void)
{
    int ret;

    // 注册平台驱动
    ret = platform_driver_register(&my_platform_driver);
    if (ret) {
        printk(KERN_ERR "Failed to register platform driver\n");
        return ret;
    }

    printk(KERN_INFO "my_platform_driver: Platform driver initialized\n");

    return 0;
}

// 模块退出函数
static void __exit my_platform_driver_exit(void)
{
    // 注销平台驱动
    platform_driver_unregister(&my_platform_driver);

    printk(KERN_INFO "my_platform_driver: Platform driver exited\n");
}

module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
